#include "TimeUnit.hpp"
#include <cstdint>
#include <ctime>
#include <string>

using namespace DBServer::Base::Timer;

Time::Time()
{
    // POSIX API
    gettimeofday(&tv, &tz);
}

Time::Time(const struct timeval& _tv)
{
    tv = _tv;
}

auto Time::operator=(const Time& _time) -> void
{
    tv = _time.tv;
}

auto Time::operator-(Time& _time) -> Time
{
    struct timeval _tv;
    _tv.tv_sec = _time.tv.tv_sec - tv.tv_sec;
    _tv.tv_usec = _time.tv.tv_usec - tv.tv_usec;
    return Time(static_cast<const struct timeval>(_tv));
}

auto Time::operator>(Time& _time) -> bool
{
    if (_time.tv.tv_sec != tv.tv_sec) 
        return _time.tv.tv_sec < tv.tv_sec;
    return _time.tv.tv_usec < tv.tv_usec;
}

auto Time::operator<(Time& _time) -> bool
{
    if (_time.tv.tv_sec != tv.tv_sec) 
        return _time.tv.tv_sec > tv.tv_sec;
    return _time.tv.tv_usec > tv.tv_usec;
}

auto Time::operator==(Time& _time) -> bool
{
    return (_time.tv.tv_sec == tv.tv_sec) && 
        (_time.tv.tv_usec == tv.tv_usec);
}

auto Time::operator>=(Time& _time) -> bool
{
    if (_time.tv.tv_sec != tv.tv_sec) 
        return _time.tv.tv_sec <= tv.tv_sec;
    return _time.tv.tv_usec <= tv.tv_usec;
}

auto Time::operator<=(Time& _time) -> bool
{
    if (_time.tv.tv_sec != tv.tv_sec) 
        return _time.tv.tv_sec >= tv.tv_sec;
    return _time.tv.tv_usec >= tv.tv_usec;
}

auto Time::operator+=(long long sec) -> void
{
    tv.tv_sec += sec;
}

auto Time::operator-=(long long sec) -> void
{
    tv.tv_sec -= sec;
}

auto Time::later(long long sec) -> void
{
    tv.tv_sec += sec;
}

auto Time::cur() -> void
{
    gettimeofday(&tv, &tz);
}

auto Time::format() -> std::string
{
    time_t time;
    char str_t[26] = {0};
 
    time = tv.tv_sec;
 
    struct tm* p_time = localtime(&time); 
    strftime(str_t, 26, "%Y-%m-%d %H:%M:%S\n", p_time);

    return str_t;
}

auto Time::GET_CUR() -> char *
{
    struct timeval tv; 
    time_t time;
    static char str_t[26] = {0};
 
    gettimeofday (&tv, NULL);
 
    time = tv.tv_sec;
 
    struct tm* p_time = localtime(&time); 
    strftime(str_t, 26, "%Y-%m-%d %H:%M:%S", p_time);

    return str_t;
}

auto Time::is_timeout() -> bool
{
    struct timeval _tv;
    gettimeofday(&_tv, nullptr);

    return (tv.tv_sec < _tv.tv_sec) ||
            (tv.tv_sec == _tv.tv_sec && tv.tv_usec < _tv.tv_usec);
}

auto Time::get_time() -> long long
{
    return tv.tv_sec;
}

auto Time::get_time_ms() -> std::uint64_t {
    return tv.tv_sec * 1000ul + tv.tv_usec / 1000ul;
}

auto Time::get_time_us() -> std::uint64_t {
    return tv.tv_sec * 1000ul * 1000ul + tv.tv_usec;
}